--------------------
--注意，该代码没有做按钮消抖
--------------------
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_arith.ALL;
USE IEEE.numeric_std.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY Question20 IS
  PORT (
    clk          : IN STD_LOGIC; --使用100Hz的时钟
    change_speed : IN STD_LOGIC;
    change_mode  : IN STD_LOGIC;
    out_led      : OUT STD_LOGIC_VECTOR(15 DOWNTO 0) --使用16个LED

  );
END Question20;

ARCHITECTURE arch OF Question20 IS
  TYPE ClockMode IS ARRAY (0 TO 1) OF INTEGER RANGE 0 TO 511;
  SIGNAL clk1            : STD_LOGIC;
  CONSTANT clk_mode_list : ClockMode                     := (4, 9);
  SIGNAL mode_num        : INTEGER RANGE 0 TO 2          := 0;
  SIGNAL clk1_count      : INTEGER RANGE 0 TO 9          := 0;
  SIGNAL ledindex        : INTEGER RANGE 0 TO 15         := 0;
  SIGNAL ans             : STD_LOGIC_VECTOR(15 DOWNTO 0) := X"0000";
  SIGNAL clk_now_num     : INTEGER RANGE 0 TO 1          := 0;
  SIGNAL model1_circle   : STD_LOGIC                     := '1';
  SIGNAL mode3_count     : INTEGER RANGE 0 TO 7          := 0;
BEGIN
  PROCESS (clk)
  BEGIN
    IF clk'event AND clk = '1' THEN
      IF clk1_count = clk_mode_list(clk_now_num) THEN
        clk1       <= '1';
        clk1_count <= 0;
      ELSE
        clk1       <= '0';
        clk1_count <= clk1_count + 1;
      END IF;
    END IF;
  END PROCESS;

  PROCESS (clk, change_speed)
  BEGIN
    IF change_speed'event AND change_speed = '1' THEN
      IF clk_now_num = 1 THEN
        clk_now_num <= 0;
      ELSE
        clk_now_num <= clk_now_num + 1;
      END IF;
    END IF;
  END PROCESS; -- change_clock

  PROCESS (clk, change_mode)
  BEGIN
    IF change_mode'event AND change_mode = '1' THEN
      IF mode_num = 2 THEN
        mode_num <= 0;
      ELSE
        mode_num <= mode_num + 1;
      END IF;
    END IF;
  END PROCESS; -- change_mode

  PROCESS (clk1)
  BEGIN
    IF clk1'event AND clk1 = '1' THEN
      IF mode_num = 0 THEN
        IF ledindex = 15 THEN
          ledindex      <= 0;
          ans(ledindex) <= model1_circle;
          CASE(model1_circle) IS
            WHEN '0' => model1_circle <= '1';
            WHEN '1' => model1_circle <= '0';
          END CASE;
        ELSE
          ans(ledindex) <= model1_circle;
          ledindex      <= ledindex + 1;
        END IF;
      ELSIF 1 = mode_num THEN
        IF model1_circle = '1' THEN
          ans           <= X"AAAA";
          model1_circle <= '0';
        ELSE
          ans           <= X"5555";
          model1_circle <= '1';
        END IF;
      ELSIF 2 = mode_num THEN
        CASE(mode3_count) IS
          WHEN 0      => ans <= X"1818";
          WHEN 1      => ans <= X"2424";
          WHEN 2      => ans <= X"4242";
          WHEN 3      => ans <= X"8181";
          WHEN OTHERS => NULL;
        END CASE;
        IF mode3_count = 3 THEN
          mode3_count <= 0;
        ELSE
          mode3_count <= mode3_count + 1;
        END IF;
      END IF;
      out_led <= ans;
    END IF;
  END PROCESS; -- modechange
END arch;